/***************************************************************************************
 *
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
 *
 *  By downloading, copying, installing or using the software you agree to this license.
 *  If you do not agree to this license, do not download, install, 
 *  copy or use the software.
 *
 *  Copyright (C) 2010-2014, Happytimesoft Corporation, all rights reserved.
 *
 *  Redistribution and use in binary forms, with or without modification, are permitted.
 *
 *  Unless required by applicable law or agreed to in writing, software distributed 
 *  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 *  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
 *  language governing permissions and limitations under the License.
 *
****************************************************************************************/

#include "sys_inc.h"
#include "onvif.h"
#include "onvif_device.h"
#include "xml_node.h"
#include "onvif_event.h"
#include "onvif_util.h"


/***************************************************************************************/
ONVIF_CFG g_onvif_cfg;
ONVIF_CLS g_onvif_cls;


/***************************************************************************************/

const char * onvif_get_video_encoding_str(E_VIDEO_ENCODING encoding)
{
    switch (encoding)
    {
    case VIDEO_ENCODING_JPEG:
        return "JPEG";

    case VIDEO_ENCODING_MPEG4:
        return "MPEG4";

    case VIDEO_ENCODING_H264:
        return "H264";
    }

    return "H264";
}

const char * onvif_get_audio_encoding_str(E_AUDIO_ENCODING encoding)
{
    switch (encoding)
    {
    case AUDIO_ENCODING_G711:
        return "G711";

    case AUDIO_ENCODING_G726:
    	return "G726";

    case AUDIO_ENCODING_AAC:
    	return "AAC";
    }

    return "G711";
}


const char * onvif_get_h264_profile_str(E_H264_PROFILE profile)
{
    switch (profile)
    {
    case H264_PROFILE_Baseline:
        return "Baseline";

    case H264_PROFILE_Extended:
        return "Extended";

    case H264_PROFILE_High:
        return "High";

    case H264_PROFILE_Main:
        return "Main";
    }

    return "Baseline";
}

const char * onvif_get_mpeg4_profile_str(E_MPEG4_PROFILE profile)
{
    switch (profile)
    {
    case MPEG4_PROFILE_SP:
        return "SP";

    case MPEG4_PROFILE_ASP:
        return "ASP";    
    }

    return "SP";
}


const char * onvif_get_ptz_status_str(E_PTZ_STATUS ptz_status)
{
	if (PTZ_STA_IDLE == ptz_status)
	{
		return "IDLE";
	}
	else if (PTZ_STA_MOVING == ptz_status)
	{
		return "MOVING";
	}
	else
	{
		return "UNKNOWN";
	}
}


E_CAP_CATEGORY onvif_get_cap_category(const char * cateory)
{
	if (NULL == cateory)
	{
		return CAP_CATEGORY_INVALID;
	}
	
	if (strcasecmp(cateory, "Media") == 0)
    {
        return CAP_CATEGORY_MEDIA;
    }
    else if (strcasecmp(cateory, "Device") == 0)
    {
        return CAP_CATEGORY_DEVICE;
    }
    else if (strcasecmp(cateory, "Analytics") == 0)
    {
        return CAP_CATEGORY_ANALYTICS;
    }
    else if (strcasecmp(cateory, "Events") == 0)
    {
        return CAP_CATEGORY_EVENTS;
    }
    else if (strcasecmp(cateory, "Imaging") == 0)
    {
        return CAP_CATEGORY_IMAGE;
    }
    else if (strcasecmp(cateory, "PTZ") == 0)
    {
        return CAP_CATEGORY_PTZ;
    }
    else if (strcasecmp(cateory, "All") == 0)
    {
        return CAP_CATEGORY_ALL;
    }

    return CAP_CATEGORY_INVALID;
}

ONVIF_PROFILE * onvif_find_profile(const char * token)
{
    ONVIF_PROFILE * profile = g_onvif_cfg.profiles;
    
    if (NULL == token)
    {
        return NULL;
    }

    while (profile)
    {
        if (strcasecmp(token, profile->token) == 0)
        {
            return profile;
        }
        
        profile = profile->next;
    }

    return NULL;
}

ONVIF_V_SRC * onvif_find_video_source(const char * token)
{
    ONVIF_V_SRC * video_source = g_onvif_cfg.video_src;
    
    if (NULL == token)
    {
        return NULL;
    }

    while (video_source)
    {
        if (strcasecmp(token, video_source->token) == 0)
        {
            return video_source;
        }
        
        video_source = video_source->next;
    }

    return NULL;
}

ONVIF_A_SRC * onvif_find_audio_source(const char * token)
{
    ONVIF_A_SRC * audio_source = g_onvif_cfg.audio_src;
    
    if (NULL == token)
    {
        return NULL;
    }

    while (audio_source)
    {
        if (strcasecmp(token, audio_source->token) == 0)
        {
            return audio_source;
        }
        
        audio_source = audio_source->next;
    }

    return NULL;
}


ONVIF_V_ENC * onvif_find_video_encoder(const char * token)
{
    ONVIF_V_ENC * video_encoder = g_onvif_cfg.video_enc;
    
    if (NULL == token)
    {
        return NULL;
    }

    while (video_encoder)
    {
        if (strcasecmp(token, video_encoder->token) == 0)
        {
            return video_encoder;
        }
        
        video_encoder = video_encoder->next;
    }

    return NULL;
}

ONVIF_A_ENC * onvif_find_audio_encoder(const char * token)
{
    ONVIF_A_ENC * audio_encoder = g_onvif_cfg.audio_enc;
    
    if (NULL == token)
    {
        return NULL;
    }

    while (audio_encoder)
    {
        if (strcasecmp(token, audio_encoder->token) == 0)
        {
            return audio_encoder;
        }
        
        audio_encoder = audio_encoder->next;
    }

    return NULL;
}



int onvif_get_video_encoding(const char * encoding)
{
	if (strcasecmp(encoding, "JPEG") == 0)
	{
		return VIDEO_ENCODING_JPEG;
	}
	else if (strcasecmp(encoding, "MPEG4") == 0)
	{
		return VIDEO_ENCODING_MPEG4;
	}
	else
	{
		return VIDEO_ENCODING_H264;
	}
}

int onvif_get_audio_encoding(const char * encoding)
{
	if (strcasecmp(encoding, "G726") == 0)
	{
		return AUDIO_ENCODING_G726;
	}
	else if (strcasecmp(encoding, "AAC") == 0)
	{
		return AUDIO_ENCODING_AAC;
	}
	else
	{
		return AUDIO_ENCODING_G711;
	}
}


int onvif_get_h264_profile(const char * profile)
{
	if (strcasecmp(profile, "Main") == 0)
	{
		return H264_PROFILE_Main;
	}
	else if (strcasecmp(profile, "Extended") == 0)
	{
		return H264_PROFILE_Extended;
	}
	else if (strcasecmp(profile, "High") == 0)
	{
		return H264_PROFILE_High;
	}
	else
	{
		return H264_PROFILE_Baseline;
	}
}

int onvif_get_mpeg4_profile(const char * profile)
{
	if (strcasecmp(profile, "ASP") == 0)
	{
		return MPEG4_PROFILE_ASP;
	}
	else
	{
		return MPEG4_PROFILE_SP;
	}
}


ONVIF_V_SRC * onvif_find_video_source(int w, int h)
{
	ONVIF_V_SRC * p_v_src = g_onvif_cfg.video_src;
	while (p_v_src)
	{
		if (p_v_src->width == w && p_v_src->height == h)
		{
			break;
		}

		p_v_src = p_v_src->next;
	}

	return p_v_src;
}

ONVIF_V_SRC * onvif_add_video_source(int w, int h)
{
	ONVIF_V_SRC * p_v_src = (ONVIF_V_SRC *) malloc(sizeof(ONVIF_V_SRC));
	if (NULL == p_v_src)
	{
		return NULL;
	}

	memset(p_v_src, 0, sizeof(ONVIF_V_SRC));

	p_v_src->x = 0;
	p_v_src->y = 0;
	p_v_src->width = w;
	p_v_src->height = h;

	p_v_src->use_count = 0;

	snprintf(p_v_src->name, ONVIF_NAME_LEN, "V_SRC_00%d", g_onvif_cls.v_src_idx);
    snprintf(p_v_src->token, ONVIF_TOKEN_LEN, "V_SRC_00%d", g_onvif_cls.v_src_idx);
    snprintf(p_v_src->source_token, ONVIF_TOKEN_LEN, "V_SRC_00%d", g_onvif_cls.v_src_idx);

    g_onvif_cls.v_src_idx++;

	ONVIF_V_SRC * p_tmp = g_onvif_cfg.video_src;
	if (NULL == p_tmp)
	{
		g_onvif_cfg.video_src = p_v_src;
	}
	else
	{
		while (p_tmp && p_tmp->next) p_tmp = p_tmp->next;

		p_tmp->next = p_v_src;
	}

	return p_v_src;
}


ONVIF_V_SRC * onvif_parse_video_source(XMLN * p_video_source)
{
	int w = 0, h = 0;
	
	XMLN * p_width = xml_node_get(p_video_source, "width");
	if (p_width && p_width->data)
	{
		w = atoi(p_width->data);
	}

	XMLN * p_height = xml_node_get(p_video_source, "height");
	if (p_height && p_height->data)
	{
		h = atoi(p_height->data);
	}

	if (w == 0 || h == 0)
	{
		return NULL;
	}
	
	ONVIF_V_SRC * p_v_src = NULL;
	
	if (g_onvif_cfg.merge_src == 1)
	{
		p_v_src = onvif_find_video_source(w, h);
		if (p_v_src)
		{
			return p_v_src;
		}
	}

	p_v_src = onvif_add_video_source(w, h);

	return p_v_src;
}

void onvif_parse_h264_options(XMLN * p_video_encoder, ONVIF_V_ENC * p_v_enc)
{
	XMLN * p_h264 = xml_node_get(p_video_encoder, "h264");
	if (NULL == p_h264)
	{
		return;
	}

	XMLN * p_gov_length = xml_node_get(p_h264, "gov_length");
	if (p_gov_length && p_gov_length->data)
	{
		p_v_enc->gov_len = atoi(p_gov_length->data);
	}

	XMLN * p_h264_profile = xml_node_get(p_h264, "h264_profile");
	if (p_h264_profile && p_h264_profile->data)
	{
		p_v_enc->profile = onvif_get_h264_profile(p_h264_profile->data);
	}
}

void onvif_parse_mpeg4_options(XMLN * p_video_encoder, ONVIF_V_ENC * p_v_enc)
{
	XMLN * p_mpeg4 = xml_node_get(p_video_encoder, "mpeg4");
	if (NULL == p_mpeg4)
	{
		return;
	}

	XMLN * p_gov_length = xml_node_get(p_mpeg4, "gov_length");
	if (p_gov_length && p_gov_length->data)
	{
		p_v_enc->gov_len = atoi(p_gov_length->data);
	}

	XMLN * p_mpeg4_profile = xml_node_get(p_mpeg4, "mpeg4_profile");
	if (p_mpeg4_profile && p_mpeg4_profile->data)
	{
		p_v_enc->profile = onvif_get_mpeg4_profile(p_mpeg4_profile->data);
	}
}


ONVIF_V_ENC * onvif_find_video_encoder(ONVIF_V_ENC * p_v_enc)
{
	ONVIF_V_ENC * p_v_enc_ = g_onvif_cfg.video_enc;
	while (p_v_enc_)
	{
		if (p_v_enc_->width == p_v_enc->width && 
			p_v_enc_->height == p_v_enc->height && 
			p_v_enc_->quality == p_v_enc->quality && 
			p_v_enc_->session_timeout == p_v_enc->session_timeout && 
			p_v_enc_->framerate_limit == p_v_enc->framerate_limit && 
			p_v_enc_->encoding_interval == p_v_enc->encoding_interval && 
			p_v_enc_->bitrate_limit == p_v_enc->bitrate_limit && 
			p_v_enc_->encoding == p_v_enc->encoding_interval && 
			p_v_enc_->gov_len == p_v_enc->gov_len && 
			p_v_enc_->profile == p_v_enc->profile)
		{
			break;
		}

		p_v_enc_ = p_v_enc_->next;
	}

	return p_v_enc_;
}

ONVIF_V_ENC * onvif_add_video_encoder(ONVIF_V_ENC * p_v_enc)
{
	ONVIF_V_ENC * p_v_enc_ = (ONVIF_V_ENC *) malloc(sizeof(ONVIF_V_ENC));
	if (NULL == p_v_enc_)
	{
		return NULL;
	}

	memset(p_v_enc_, 0, sizeof(ONVIF_V_ENC));

	p_v_enc_->use_count = 0;
	p_v_enc_->width = p_v_enc->width;
	p_v_enc_->height = p_v_enc->height;
	p_v_enc_->quality = p_v_enc->quality;
	p_v_enc_->session_timeout = p_v_enc->session_timeout;
	p_v_enc_->framerate_limit = p_v_enc->framerate_limit;
	p_v_enc_->encoding_interval = p_v_enc->encoding_interval;
	p_v_enc_->bitrate_limit = p_v_enc->bitrate_limit;
	p_v_enc_->encoding = p_v_enc->encoding;
	p_v_enc_->gov_len = p_v_enc->gov_len;
	p_v_enc_->profile = p_v_enc->profile;

	snprintf(p_v_enc_->name, ONVIF_NAME_LEN, "V_ENC_00%d", g_onvif_cls.v_enc_idx);
    snprintf(p_v_enc_->token, ONVIF_TOKEN_LEN, "V_ENC_00%d", g_onvif_cls.v_enc_idx);

    g_onvif_cls.v_enc_idx++;

	ONVIF_V_ENC * p_tmp = g_onvif_cfg.video_enc;
	if (NULL == p_tmp)
	{
		g_onvif_cfg.video_enc = p_v_enc_;
	}
	else
	{
		while (p_tmp && p_tmp->next) p_tmp = p_tmp->next;

		p_tmp->next = p_v_enc_;
	}

	return p_v_enc_;
}


ONVIF_V_ENC * onvif_parse_video_encoder(XMLN * p_video_encoder)
{
	ONVIF_V_ENC v_enc;
	memset(&v_enc, 0, sizeof(ONVIF_V_ENC));
	
	XMLN * p_width = xml_node_get(p_video_encoder, "width");
	if (p_width && p_width->data)
	{
		v_enc.width = atoi(p_width->data);
	}

	XMLN * p_height = xml_node_get(p_video_encoder, "height");
	if (p_height && p_height->data)
	{
		v_enc.height = atoi(p_height->data);
	}

	XMLN * p_quality = xml_node_get(p_video_encoder, "quality");
	if (p_quality && p_quality->data)
	{
		v_enc.quality = atoi(p_quality->data);
	}

	XMLN * p_session_timeout = xml_node_get(p_video_encoder, "session_timeout");
	if (p_session_timeout && p_session_timeout->data)
	{
		v_enc.session_timeout = atoi(p_session_timeout->data);
	}

	XMLN * p_framerate = xml_node_get(p_video_encoder, "framerate");
	if (p_framerate && p_framerate->data)
	{
		v_enc.framerate_limit = atoi(p_framerate->data);
	}

	XMLN * p_encoding_interval = xml_node_get(p_video_encoder, "encoding_interval");
	if (p_encoding_interval && p_encoding_interval->data)
	{
		v_enc.encoding_interval = atoi(p_encoding_interval->data);
	}

	XMLN * p_bitrate_limit = xml_node_get(p_video_encoder, "bitrate_limit");
	if (p_bitrate_limit && p_bitrate_limit->data)
	{
		v_enc.bitrate_limit = atoi(p_bitrate_limit->data);
	}

	XMLN * p_encoding = xml_node_get(p_video_encoder, "encoding");
	if (p_encoding && p_encoding->data)
	{
		v_enc.encoding = (E_VIDEO_ENCODING) onvif_get_video_encoding(p_encoding->data);
	}

	if (VIDEO_ENCODING_MPEG4 == v_enc.encoding)
	{
		onvif_parse_mpeg4_options(p_video_encoder, &v_enc);
	}
	else if (VIDEO_ENCODING_H264 == v_enc.encoding)
	{
		onvif_parse_h264_options(p_video_encoder, &v_enc);
	}

	ONVIF_V_ENC * p_v_enc = onvif_find_video_encoder(&v_enc);
	if (p_v_enc)
	{
		return p_v_enc;
	}

	p_v_enc = onvif_add_video_encoder(&v_enc);

	return p_v_enc;
}

ONVIF_A_SRC * onvif_find_audio_source()
{
	return g_onvif_cfg.audio_src;
}

ONVIF_A_SRC * onvif_add_audio_source()
{
	ONVIF_A_SRC * p_a_src = (ONVIF_A_SRC *) malloc(sizeof(ONVIF_A_SRC));
	if (NULL == p_a_src)
	{
		return NULL;
	}

	memset(p_a_src, 0, sizeof(ONVIF_A_SRC));

	p_a_src->use_count = 0;

	snprintf(p_a_src->name, ONVIF_NAME_LEN, "A_SRC_00%d", g_onvif_cls.a_src_idx);
    snprintf(p_a_src->token, ONVIF_TOKEN_LEN, "A_SRC_00%d", g_onvif_cls.a_src_idx);
    snprintf(p_a_src->source_token, ONVIF_TOKEN_LEN, "A_SRC_00%d", g_onvif_cls.a_src_idx);

    g_onvif_cls.a_src_idx++;

	ONVIF_A_SRC * p_tmp = g_onvif_cfg.audio_src;
	if (NULL == p_tmp)
	{
		g_onvif_cfg.audio_src = p_a_src;
	}
	else
	{
		while (p_tmp && p_tmp->next) p_tmp = p_tmp->next;

		p_tmp->next = p_a_src;
	}

	return p_a_src;
}


ONVIF_A_SRC * onvif_parse_audio_source(XMLN * p_audio_source)
{	
	ONVIF_A_SRC * p_a_src = onvif_find_audio_source();
	if (p_a_src)
	{
		return p_a_src;
	}

	p_a_src = onvif_add_audio_source();

	return p_a_src;
}

ONVIF_A_ENC * onvif_find_audio_encoder(ONVIF_A_ENC * p_a_enc)
{
	ONVIF_A_ENC * p_a_enc_ = g_onvif_cfg.audio_enc;
	while (p_a_enc_)
	{
		if (p_a_enc_->session_timeout == p_a_enc->session_timeout &&
			p_a_enc_->sample_rate == p_a_enc->sample_rate && 
			p_a_enc_->bitrate == p_a_enc->bitrate && 
			p_a_enc->encoding == p_a_enc->encoding)
		{
			break;
		}

		p_a_enc_ = p_a_enc_->next;
	}

	return p_a_enc_;
}

ONVIF_A_ENC * onvif_add_audio_encoder(ONVIF_A_ENC * p_a_enc)
{
	ONVIF_A_ENC * p_a_enc_ = (ONVIF_A_ENC *) malloc(sizeof(ONVIF_A_ENC));
	if (NULL == p_a_enc_)
	{
		return NULL;
	}

	memset(p_a_enc_, 0, sizeof(ONVIF_A_ENC));

	p_a_enc_->use_count = 0;
	p_a_enc_->session_timeout = p_a_enc->session_timeout;
	p_a_enc_->sample_rate = p_a_enc->sample_rate;
	p_a_enc_->bitrate = p_a_enc->bitrate;	
	p_a_enc_->encoding = p_a_enc->encoding;

	snprintf(p_a_enc_->name, ONVIF_NAME_LEN, "A_ENC_00%d", g_onvif_cls.a_enc_idx);
    snprintf(p_a_enc_->token, ONVIF_TOKEN_LEN, "A_ENC_00%d", g_onvif_cls.a_enc_idx);

    g_onvif_cls.a_enc_idx++;

	ONVIF_A_ENC * p_tmp = g_onvif_cfg.audio_enc;
	if (NULL == p_tmp)
	{
		g_onvif_cfg.audio_enc = p_a_enc_;
	}
	else
	{
		while (p_tmp && p_tmp->next) p_tmp = p_tmp->next;

		p_tmp->next = p_a_enc_;
	}

	return p_a_enc_;
}


ONVIF_A_ENC * onvif_parse_audio_encoder(XMLN * p_audio_encoder)
{
	ONVIF_A_ENC a_enc;
	memset(&a_enc, 0, sizeof(ONVIF_A_ENC));
	
	XMLN * p_session_timeout = xml_node_get(p_audio_encoder, "session_timeout");
	if (p_session_timeout && p_session_timeout->data)
	{
		a_enc.session_timeout = atoi(p_session_timeout->data);
	}

	XMLN * p_sample_rate = xml_node_get(p_audio_encoder, "sample_rate");
	if (p_sample_rate && p_sample_rate->data)
	{
		a_enc.sample_rate = atoi(p_sample_rate->data);
	}

	XMLN * p_bitrate = xml_node_get(p_audio_encoder, "bitrate");
	if (p_bitrate && p_bitrate->data)
	{
		a_enc.bitrate = atoi(p_bitrate->data);
	}	

	XMLN * p_encoding = xml_node_get(p_audio_encoder, "encoding");
	if (p_encoding && p_encoding->data)
	{
		a_enc.encoding = (E_AUDIO_ENCODING) onvif_get_audio_encoding(p_encoding->data);
	}

	ONVIF_A_ENC * p_a_enc = onvif_find_audio_encoder(&a_enc);
	if (p_a_enc)
	{
		return p_a_enc;
	}

	p_a_enc = onvif_add_audio_encoder(&a_enc);

	return p_a_enc;
}

ONVIF_PROFILE * onvif_add_profile(BOOL fixed)
{
	ONVIF_PROFILE * p_profile = (ONVIF_PROFILE *) malloc(sizeof(ONVIF_PROFILE));
	if (NULL == p_profile)
	{
		return NULL;
	}

	memset(p_profile, 0, sizeof(ONVIF_PROFILE));

	p_profile->fixed = fixed;

	snprintf(p_profile->name, ONVIF_NAME_LEN, "PROFILE_00%d", g_onvif_cls.profile_idx);
    snprintf(p_profile->token, ONVIF_TOKEN_LEN, "PROFILE_00%d", g_onvif_cls.profile_idx);

    g_onvif_cls.profile_idx++;

	ONVIF_PROFILE * p_tmp = g_onvif_cfg.profiles;
	if (NULL == p_tmp)
	{
		g_onvif_cfg.profiles = p_profile;
	}
	else
	{
		while (p_tmp && p_tmp->next) p_tmp = p_tmp->next;

		p_tmp->next = p_profile;
	}

	return p_profile;
}

void onvif_parse_profile(XMLN * p_profile)
{
	ONVIF_PROFILE * profile = onvif_add_profile(TRUE);
	if (NULL == profile)
	{
		return;
	}
	
	XMLN * p_video_source = xml_node_get(p_profile, "video_source");
	if (p_video_source)
	{
		profile->video_src = onvif_parse_video_source(p_video_source);
		profile->video_src->use_count++;
	}

	XMLN * p_video_encoder = xml_node_get(p_profile, "video_encoder");
	if (p_video_encoder)
	{
		profile->video_enc = onvif_parse_video_encoder(p_video_encoder);
		profile->video_enc->use_count++;
	}

	XMLN * p_audio_source = xml_node_get(p_profile, "audio_source");
	if (p_audio_source)
	{
		profile->audio_src = onvif_parse_audio_source(p_audio_source);
		profile->audio_src->use_count++;
	}
	
	XMLN * p_audio_encoder = xml_node_get(p_profile, "audio_encoder");
	if (p_audio_encoder)
	{
		profile->audio_enc = onvif_parse_audio_encoder(p_audio_encoder);
		profile->audio_enc->use_count++;
	}

	XMLN * p_stream_uri = xml_node_get(p_profile, "stream_uri");
	if (p_stream_uri && p_stream_uri->data && strlen(p_stream_uri->data) > 0)
	{
		strncpy(profile->stream_uri, p_stream_uri->data, sizeof(profile->stream_uri));
	}
	else
	{
		if (strlen(g_onvif_cfg.serv_ip) > 0)
		{
			sprintf(profile->stream_uri, "rtsp://%s/test.264", g_onvif_cfg.serv_ip);
		}
		else
		{
			sprintf(profile->stream_uri, "rtsp://%s/test.264", onvif_get_local_ip());
		}
	}
}

BOOL onvif_is_scope_exist(const char * scope)
{
	for (int i = 0; i < MAX_SCOPE_NUMS; i++)
	{
		if (strcmp(scope, g_onvif_cfg.scopes[i].scope) == 0)
		{
			return TRUE;
		}
	}

	return FALSE;	
}

ONVIF_SCOPE * onvif_find_scope(const char * scope)
{
	for (int i = 0; i < MAX_SCOPE_NUMS; i++)
	{
		if (strcmp(g_onvif_cfg.scopes[i].scope, scope) == 0)
		{
			return &g_onvif_cfg.scopes[i];
		}
	}

	return NULL;
}

ONVIF_SCOPE * onvif_get_idle_scope()
{
	for (int i = 0; i < MAX_SCOPE_NUMS; i++)
	{
		if (g_onvif_cfg.scopes[i].scope[0] == '\0')
		{
			return &g_onvif_cfg.scopes[i];
		}
	}

	return NULL;
}

int onvif_add_scope(const char * scope, BOOL fixed)
{
	if (onvif_is_scope_exist(scope) == TRUE)
	{
		return -1;
	}

	ONVIF_SCOPE * p_scope = onvif_get_idle_scope();
	if (p_scope)
	{
		p_scope->fixed = fixed;
		strncpy(p_scope->scope, scope, sizeof(p_scope->scope)-1);
		return 0;
	}

	return -2;
}

ONVIF_RET onvif_add_scopes(ONVIF_SCOPE * p_scope, int scope_max)
{
	for (int i = 0; i < scope_max; i++)
	{
		if (p_scope[i].scope[0] == '\0')
		{
			break;
		}

		if (onvif_is_scope_exist(p_scope[i].scope))
		{
			continue;
		}
		
		ONVIF_SCOPE * p_item = onvif_get_idle_scope();
		if (p_item)
		{
			p_item->fixed = p_scope[i].fixed;
			strcpy(p_item->scope, p_scope[i].scope);
		}
		else
		{
			return ONVIF_ERR_TOO_MANY_SCOPES;
		}
	}
	
	return ONVIF_OK;
}

ONVIF_RET onvif_set_scopes(ONVIF_SCOPE * p_scope, int scope_max)
{
	ONVIF_SCOPE * p_item = NULL;
	
	for (int i = 0; i < scope_max; i++)
	{
		if (p_scope[i].scope[0] == '\0')
		{
			break;
		}
		
		p_item = onvif_find_scope(p_scope[i].scope);
		if (p_item && p_item->fixed)
		{
			return ONVIF_ERR_SCOPE_OVERWRITE;
		}
	}
	
	for (int i = 0; i < MAX_SCOPE_NUMS; i++)
	{
		if (g_onvif_cfg.scopes[i].fixed == FALSE && g_onvif_cfg.scopes[i].scope[0] != '\0')
		{
			memset(&g_onvif_cfg.scopes[i], 0, sizeof(ONVIF_SCOPE));
		}
	}
	
	return onvif_add_scopes(p_scope, scope_max);
}

ONVIF_RET onvif_remove_scopes(ONVIF_SCOPE * p_scope, int scope_max)
{
	ONVIF_SCOPE * p_item = NULL;
	
	for (int i = 0; i < scope_max; i++)
	{
		if (p_scope[i].scope[0] == '\0')
		{
			break;
		}

		p_item = onvif_find_scope(p_scope[i].scope);
		if (NULL == p_item)
		{
			return ONVIF_ERR_NO_SCOPE;
		}
		else if (p_item->fixed)
		{
			return ONVIF_ERR_FIXED_SCOPE;
		}
	}	

	for (int i = 0; i < scope_max; i++)
	{
		if (p_scope[i].scope[0] == '\0')
		{
			break;
		}

		p_item = onvif_find_scope(p_scope[i].scope);
		if (NULL != p_item && p_item->fixed == FALSE)
		{
			memset(p_item, 0, sizeof(ONVIF_SCOPE));
		}
	}	

	return ONVIF_OK;
}

void onvif_parse_information_cfg(XMLN * p_node)
{
	XMLN * p_Manufacturer = xml_node_get(p_node, "Manufacturer");
	if (p_Manufacturer && p_Manufacturer->data)
	{
		strncpy(g_onvif_cfg.manufacturer, p_Manufacturer->data, sizeof(g_onvif_cfg.manufacturer)-1);
	}

	XMLN * p_Model = xml_node_get(p_node, "Model");
	if (p_Model && p_Model->data)
	{
		strncpy(g_onvif_cfg.model, p_Model->data, sizeof(g_onvif_cfg.model)-1);
	}
	
	XMLN * p_FirmwareVersion = xml_node_get(p_node, "FirmwareVersion");
	if (p_FirmwareVersion && p_FirmwareVersion->data)
	{
		strncpy(g_onvif_cfg.firmware_version, p_FirmwareVersion->data, sizeof(g_onvif_cfg.firmware_version)-1);
	}

	XMLN * p_SerialNumber = xml_node_get(p_node, "SerialNumber");
	if (p_SerialNumber && p_SerialNumber->data)
	{
		strncpy(g_onvif_cfg.serial_number, p_SerialNumber->data, sizeof(g_onvif_cfg.serial_number)-1);
	}

	XMLN * p_HardwareId = xml_node_get(p_node, "HardwareId");
	if (p_HardwareId && p_HardwareId->data)
	{
		strncpy(g_onvif_cfg.hardware_id, p_HardwareId->data, sizeof(g_onvif_cfg.hardware_id));
	}
}

void onvif_parse_event_cfg(XMLN * p_event)
{
	XMLN * p_renew_interval = xml_node_get(p_event, "renew_interval");
	if (p_renew_interval && p_renew_interval->data)
	{
		g_onvif_cfg.evt_renew_time = atoi(p_renew_interval->data);
	}

	XMLN * p_simulate_enable = xml_node_get(p_event, "simulate_enable");
	if (p_simulate_enable && p_simulate_enable->data)
	{
		g_onvif_cfg.evt_sim_flag = atoi(p_simulate_enable->data);
	}
	
	XMLN * p_simulate_interval = xml_node_get(p_event, "simulate_interval");
	if (p_simulate_interval && p_simulate_interval->data)
	{
		g_onvif_cfg.evt_sim_interval = atoi(p_simulate_interval->data);
	}
}

PTZ_NODE * onvif_find_ptz_node(const char * token)
{
	PTZ_NODE * p_node = g_onvif_cfg.ptznodes;
	while (p_node)
	{
		if (strcmp(p_node->token, token) == 0)
		{
			break;
		}

		p_node = p_node->next;
	}

	return p_node;
}

PTZ_NODE * onvif_find_ptz_cfg(const char * token)
{
	PTZ_NODE * p_node = g_onvif_cfg.ptznodes;
	while (p_node)
	{
		if (strcmp(p_node->config.token, token) == 0)
		{
			break;
		}

		p_node = p_node->next;
	}

	return p_node;
}


PTZ_NODE * onvif_add_ptz_node()
{
	PTZ_NODE * p_node = (PTZ_NODE *) malloc(sizeof(PTZ_NODE));
	if (NULL == p_node)
	{
		return NULL;
	}

	memset(p_node, 0, sizeof(PTZ_NODE));

	snprintf(p_node->name, ONVIF_NAME_LEN, "NODE_00%d", g_onvif_cls.ptznode_idx);
    snprintf(p_node->token, ONVIF_TOKEN_LEN, "NODE_00%d", g_onvif_cls.ptznode_idx);
    snprintf(p_node->config.name, ONVIF_NAME_LEN, "PTZ_00%d", g_onvif_cls.ptznode_idx);
    snprintf(p_node->config.token, ONVIF_TOKEN_LEN, "PTZ_00%d", g_onvif_cls.ptznode_idx);

    g_onvif_cls.ptznode_idx++;

	PTZ_NODE * p_tmp = g_onvif_cfg.ptznodes;
	if (NULL == p_tmp)
	{
		g_onvif_cfg.ptznodes = p_node;
	}
	else
	{
		while (p_tmp && p_tmp->next) p_tmp = p_tmp->next;

		p_tmp->next = p_node;
	}

	return p_node;
}

void onvif_parse_float_range(XMLN * p_node, ONVIF_FRANGE * p_xrange, ONVIF_FRANGE * p_yrange)
{	
	XMLN * p_XRange = xml_node_get(p_node, "XRange");
	if (p_XRange)
	{
		const char * p_min = xml_attr_get(p_XRange, "min");
		if (p_min)
		{
			p_xrange->min = atof(p_min);
		}
		
		const char * p_max = xml_attr_get(p_XRange, "max");
		if (p_max)
		{
			p_xrange->max = atof(p_max);
		}
	}

	if (NULL == p_yrange)
	{
		return;
	}
	
	XMLN * p_YRange = xml_node_get(p_node, "YRange");
	if (p_YRange)
	{
		const char * p_min = xml_attr_get(p_YRange, "min");
		if (p_min)
		{
			p_yrange->min = atof(p_min);
		}
		
		const char * p_max = xml_attr_get(p_YRange, "max");
		if (p_max)
		{
			p_yrange->max = atof(p_max);
		}
	}
}

void onvif_parse_ptz_space(XMLN * p_node, PTZ_NODE * p_ptz_node)
{
	XMLN * p_AbsolutePanTiltPositionSpace = xml_node_get(p_node, "AbsolutePanTiltPositionSpace");
	if (p_AbsolutePanTiltPositionSpace)
	{
		p_ptz_node->abs_pantilt_space = 1;

		onvif_parse_float_range(p_AbsolutePanTiltPositionSpace, &p_ptz_node->abs_pantilt_x, &p_ptz_node->abs_pantilt_y);
	}

	XMLN * p_AbsoluteZoomPositionSpace = xml_node_get(p_node, "AbsoluteZoomPositionSpace");
	if (p_AbsoluteZoomPositionSpace)
	{
		p_ptz_node->abs_zoom_space = 1;

		onvif_parse_float_range(p_AbsoluteZoomPositionSpace, &p_ptz_node->abs_zoom, NULL);
	}

	XMLN * p_RelativePanTiltTranslationSpace = xml_node_get(p_node, "RelativePanTiltTranslationSpace");
	if (p_RelativePanTiltTranslationSpace)
	{
		p_ptz_node->rel_pantilt_space = 1;

		onvif_parse_float_range(p_RelativePanTiltTranslationSpace, &p_ptz_node->rel_pantilt_x, &p_ptz_node->rel_pantilt_y);
	}

	XMLN * p_RelativeZoomTranslationSpace = xml_node_get(p_node, "RelativeZoomTranslationSpace");
	if (p_RelativeZoomTranslationSpace)
	{
		p_ptz_node->rel_zoom_space = 1;

		onvif_parse_float_range(p_RelativeZoomTranslationSpace, &p_ptz_node->rel_zoom, NULL);
	}

	XMLN * p_ContinuousPanTiltVelocitySpace = xml_node_get(p_node, "ContinuousPanTiltVelocitySpace");
	if (p_ContinuousPanTiltVelocitySpace)
	{
		p_ptz_node->con_pantilt_space = 1;

		onvif_parse_float_range(p_ContinuousPanTiltVelocitySpace, &p_ptz_node->con_pantilt_x, &p_ptz_node->con_pantilt_y);
	}

	XMLN * p_ContinuousZoomVelocitySpace = xml_node_get(p_node, "ContinuousZoomVelocitySpace");
	if (p_ContinuousZoomVelocitySpace)
	{
		p_ptz_node->con_zoom_space = 1;

		onvif_parse_float_range(p_ContinuousZoomVelocitySpace, &p_ptz_node->con_zoom, NULL);
	}
	
	XMLN * p_PanTiltSpeedSpace = xml_node_get(p_node, "PanTiltSpeedSpace");
	if (p_PanTiltSpeedSpace)
	{
		p_ptz_node->pantile_speed_space = 1;

		onvif_parse_float_range(p_PanTiltSpeedSpace, &p_ptz_node->pantile_speed, NULL);
	}

	XMLN * p_ZoomSpeedSpace = xml_node_get(p_node, "ZoomSpeedSpace");
	if (p_ZoomSpeedSpace)
	{
		p_ptz_node->zoom_speed_space = 1;

		onvif_parse_float_range(p_ZoomSpeedSpace, &p_ptz_node->zoom_speed, NULL);
	}
}

void onvif_parse_ptz_node_cfg(XMLN * p_node, PTZ_CFG * p_cfg)
{
	XMLN * p_DefaultPTZSpeed = xml_node_get(p_node, "DefaultPTZSpeed");
	if (p_DefaultPTZSpeed)
	{
		const char * p_PanTiltX = xml_attr_get(p_DefaultPTZSpeed, "PanTiltX");
		if (p_PanTiltX)
		{
			p_cfg->def_pantilt_speed_x = atof(p_PanTiltX);
		}

		const char * p_PanTiltY = xml_attr_get(p_DefaultPTZSpeed, "PanTiltY");
		if (p_PanTiltY)
		{
			p_cfg->def_pantilt_speed_y = atof(p_PanTiltY);
		}

		const char * p_Zoom = xml_attr_get(p_DefaultPTZSpeed, "Zoom");
		if (p_Zoom)
		{
			p_cfg->def_zoom_speed = atof(p_Zoom);
		}
	}

	XMLN * p_DefaultPTZTimeout = xml_node_get(p_node, "DefaultPTZTimeout");
	if (p_DefaultPTZTimeout && p_DefaultPTZTimeout->data)
	{
		p_cfg->def_timeout = atoi(p_DefaultPTZTimeout->data);
	}

	XMLN * p_PanTiltLimits = xml_node_get(p_node, "PanTiltLimits");
	if (p_PanTiltLimits)
	{
		onvif_parse_float_range(p_PanTiltLimits, &p_cfg->pantilt_limits_x, &p_cfg->pantilt_limits_y);
	}

	XMLN * p_ZoomLimits = xml_node_get(p_node, "ZoomLimits");
	if (p_PanTiltLimits)
	{
		onvif_parse_float_range(p_ZoomLimits, &p_cfg->zoom_limits , NULL);
	}

	
	XMLN * p_TimeoutRange = xml_node_get(p_node, "TimeoutRange");
	if (p_TimeoutRange)
	{
		onvif_parse_float_range(p_TimeoutRange, &p_cfg->timeout_range, NULL);
	}
}

void onvif_parse_ptz_node(XMLN * p_node)
{
	PTZ_NODE * p_ptz_node = onvif_add_ptz_node();
	if (NULL == p_ptz_node)
	{
		return;
	}
	
	XMLN * p_FixedHomePosition = xml_node_get(p_node, "FixedHomePosition");
	if (p_FixedHomePosition && p_FixedHomePosition->data)
	{
		p_ptz_node->fixed_home_pos = atoi(p_FixedHomePosition->data);
	}

	XMLN * p_SupportedPTZSpaces = xml_node_get(p_node, "SupportedPTZSpaces");
	if (p_SupportedPTZSpaces)
	{
		onvif_parse_ptz_space(p_SupportedPTZSpaces, p_ptz_node);
	}

	XMLN * p_PTZConfiguration = xml_node_get(p_node, "PTZConfiguration");
	if (p_PTZConfiguration)
	{
		onvif_parse_ptz_node_cfg(p_PTZConfiguration, &p_ptz_node->config);
	}
}

void onvif_parse_ptz_cfg(XMLN * p_ptz)
{
	XMLN * p_enable = xml_node_get(p_ptz, "enable");
	if (p_enable && p_enable->data)
	{
		g_onvif_cfg.ptz_enable = atoi(p_enable->data);
	}

	XMLN * p_node = xml_node_get(p_ptz, "node");
	while (p_node && strcmp(p_node->name, "node") == 0)
	{
    	onvif_parse_ptz_node(p_node);

    	p_node = p_node->next;
	}
}

void onvif_parse_video_source_cfg(XMLN * p_node)
{
	XMLN * p_x = xml_node_soap_get(p_node, "x");
	if (p_x)
	{
		const char * p_min = xml_attr_get(p_x, "min");
		if (p_min)
		{
			g_onvif_cfg.video_src_cfg.x_min = atoi(p_min);
		}

		const char * p_max = xml_attr_get(p_x, "max");
		if (p_max)
		{
			g_onvif_cfg.video_src_cfg.x_max = atoi(p_max);
		}
	}

	XMLN * p_y = xml_node_soap_get(p_node, "y");
	if (p_y)
	{
		const char * p_min = xml_attr_get(p_y, "min");
		if (p_min)
		{
			g_onvif_cfg.video_src_cfg.y_min = atoi(p_min);
		}

		const char * p_max = xml_attr_get(p_y, "max");
		if (p_max)
		{
			g_onvif_cfg.video_src_cfg.y_max = atoi(p_max);
		}
	}

	XMLN * p_width = xml_node_soap_get(p_node, "width");
	if (p_width)
	{
		const char * p_min = xml_attr_get(p_width, "min");
		if (p_min)
		{
			g_onvif_cfg.video_src_cfg.w_min = atoi(p_min);
		}

		const char * p_max = xml_attr_get(p_width, "max");
		if (p_max)
		{
			g_onvif_cfg.video_src_cfg.w_max = atoi(p_max);
		}
	}

	XMLN * p_height = xml_node_soap_get(p_node, "height");
	if (p_height)
	{
		const char * p_min = xml_attr_get(p_height, "min");
		if (p_min)
		{
			g_onvif_cfg.video_src_cfg.h_min = atoi(p_min);
		}

		const char * p_max = xml_attr_get(p_height, "max");
		if (p_max)
		{
			g_onvif_cfg.video_src_cfg.h_max = atoi(p_max);
		}
	}
}


void onvif_parse_cfg(char * xml_buff, int rlen)
{
	XMLN * p_node = xxx_hxml_parse(xml_buff, rlen); //这里应该是返回第一个p_node的地址，后面根据这个地址找整个链表
	if (NULL == p_node)
	{
		return;
	}

    XMLN * p_serv_ip = xml_node_get(p_node, "server_ip"); //OnvifServer/onvif/xml_node.cpp 中
	if (p_serv_ip && p_serv_ip->data)
	{
		strncpy(g_onvif_cfg.serv_ip, p_serv_ip->data, sizeof(g_onvif_cfg.serv_ip)-1);
	}
	
	XMLN * p_serv_port = xml_node_get(p_node, "server_port");
	if (p_serv_port && p_serv_port->data)
	{
		g_onvif_cfg.serv_port = atoi(p_serv_port->data);
	}
	
	XMLN * p_need_auth = xml_node_get(p_node, "need_auth");
	if (p_need_auth && p_need_auth->data)
	{
		g_onvif_cfg.need_auth = atoi(p_need_auth->data);
	}

	XMLN * p_auth_user = xml_node_get(p_node, "auth_user");
	if (p_auth_user && p_auth_user->data)
	{
		strncpy(g_onvif_cfg.auth_user, p_auth_user->data, sizeof(g_onvif_cfg.auth_user)-1);
	}

	XMLN * p_auth_pass = xml_node_get(p_node, "auth_pass");
	if (p_auth_pass && p_auth_pass->data)
	{
		strncpy(g_onvif_cfg.auth_pass, p_auth_pass->data, sizeof(g_onvif_cfg.auth_pass)-1);
	}

    XMLN * p_discoverable = xml_node_get(p_node, "discoverable");
	if (p_discoverable && p_discoverable->data)
	{
		g_onvif_cfg.discoverable = atoi(p_discoverable->data);
	}

	XMLN * p_merge_source = xml_node_get(p_node, "merge_source");
	if (p_merge_source && p_merge_source->data)
	{
		g_onvif_cfg.merge_src = atoi(p_merge_source->data);
	}
	
	XMLN * p_information = xml_node_get(p_node, "information");
	if (p_information)
	{
		onvif_parse_information_cfg(p_information);
	}

	XMLN * p_video_source_config = xml_node_get(p_node, "video_source_config");
	if (p_video_source_config)
	{
		onvif_parse_video_source_cfg(p_video_source_config);
	}
	
	XMLN * p_profile = xml_node_get(p_node, "profile");
	while (p_profile && strcmp(p_profile->name, "profile") == 0)
	{
    	onvif_parse_profile(p_profile);

    	p_profile = p_profile->next;
	}

	XMLN * p_scope = xml_node_get(p_node, "scope");
	while (p_scope && strcmp(p_profile->name, "scope") == 0)
	{
		if (p_scope->data)
		{
			onvif_add_scope(p_scope->data, TRUE);
		}

		p_scope = p_scope->next;
	}

	XMLN * p_event = xml_node_get(p_node, "event");
	if (p_event)
	{
		onvif_parse_event_cfg(p_event);
	}

	XMLN * p_ptz = xml_node_get(p_node, "ptz");
	if (p_ptz)
	{
		onvif_parse_ptz_cfg(p_ptz);
	}

	// add PTZ node to profile
	ONVIF_PROFILE * profile = g_onvif_cfg.profiles;
	while (profile)
	{
		profile->ptz_node = g_onvif_cfg.ptznodes;
		
		profile = profile->next;
	}
	
	xml_node_del(p_node);
}


void onvif_init_cfg()
{
	g_onvif_cfg.discoverable = 1;
	g_onvif_cfg.serv_port = 8000;
	g_onvif_cfg.evt_sim_interval = 60;
	g_onvif_cfg.evt_sim_flag = 1;
	g_onvif_cfg.evt_renew_time = 60;

	g_onvif_cfg.datetime_ntp = 0;
    g_onvif_cfg.daylightsavings = false;
	onvif_get_timezone(g_onvif_cfg.timezone, sizeof(g_onvif_cfg.timezone));	

	// video encoder config options
	g_onvif_cfg.video_enc_cfg.quality_min = 0;
	g_onvif_cfg.video_enc_cfg.quality_max = 100;
	g_onvif_cfg.video_enc_cfg.resolution[0].w = 1920;
	g_onvif_cfg.video_enc_cfg.resolution[0].h = 1280;
	g_onvif_cfg.video_enc_cfg.resolution[1].w = 1280;
	g_onvif_cfg.video_enc_cfg.resolution[1].h = 720;
	g_onvif_cfg.video_enc_cfg.resolution[2].w = 640;
	g_onvif_cfg.video_enc_cfg.resolution[2].h = 480;
	g_onvif_cfg.video_enc_cfg.resolution[3].w = 352;
	g_onvif_cfg.video_enc_cfg.resolution[3].h = 288;
	g_onvif_cfg.video_enc_cfg.resolution[4].w = 320;
	g_onvif_cfg.video_enc_cfg.resolution[4].h = 240;

	// // jpeg config options
	g_onvif_cfg.video_enc_cfg.jpeg_opt.frame_rate_min = 1;
	g_onvif_cfg.video_enc_cfg.jpeg_opt.frame_rate_max = 30;
	g_onvif_cfg.video_enc_cfg.jpeg_opt.encoding_interval_min = 5;
	g_onvif_cfg.video_enc_cfg.jpeg_opt.encoding_interval_max = 60;

	// mpeg4 config options
	g_onvif_cfg.video_enc_cfg.mpeg4_opt.sp_profile = 1;
	g_onvif_cfg.video_enc_cfg.mpeg4_opt.gov_length_min = 10;
	g_onvif_cfg.video_enc_cfg.mpeg4_opt.gov_length_max = 60;
	g_onvif_cfg.video_enc_cfg.mpeg4_opt.frame_rate_min = 1;
	g_onvif_cfg.video_enc_cfg.mpeg4_opt.frame_rate_max = 30;
	g_onvif_cfg.video_enc_cfg.mpeg4_opt.encoding_interval_min = 5;
	g_onvif_cfg.video_enc_cfg.mpeg4_opt.encoding_interval_max = 60;

	// h264 config options
	g_onvif_cfg.video_enc_cfg.h264_opt.baseline_profile = 1;
	g_onvif_cfg.video_enc_cfg.h264_opt.main_profile = 1;
	g_onvif_cfg.video_enc_cfg.h264_opt.gov_length_min = 10;
	g_onvif_cfg.video_enc_cfg.h264_opt.gov_length_max = 60;
	g_onvif_cfg.video_enc_cfg.h264_opt.frame_rate_min = 1;
	g_onvif_cfg.video_enc_cfg.h264_opt.frame_rate_max = 30;
	g_onvif_cfg.video_enc_cfg.h264_opt.encoding_interval_min = 5;
	g_onvif_cfg.video_enc_cfg.h264_opt.encoding_interval_max = 60;

	// image setting
	g_onvif_cfg.img_cfg.BacklightCompensation_Mode = 0;
	g_onvif_cfg.img_cfg.Brightness = 50;
	g_onvif_cfg.img_cfg.ColorSaturation = 50;
	g_onvif_cfg.img_cfg.Contrast = 50;
	g_onvif_cfg.img_cfg.Exposure_Mode = 0;
	g_onvif_cfg.img_cfg.MinExposureTime = 10;
	g_onvif_cfg.img_cfg.MaxExposureTime = 40000;
	g_onvif_cfg.img_cfg.MinGain = 0;
	g_onvif_cfg.img_cfg.MaxGain = 100;
	g_onvif_cfg.img_cfg.IrCutFilter_Mode = 2;
	g_onvif_cfg.img_cfg.Sharpness = 50;
	g_onvif_cfg.img_cfg.WideDynamicRange_Mode = 0;
	g_onvif_cfg.img_cfg.WhiteBalance_Mode = 0;
	g_onvif_cfg.img_cfg.WideDynamicRange_Level = 50;

	// image config options
	g_onvif_cfg.img_opt.BacklightCompensation_OFF = 1;
	g_onvif_cfg.img_opt.BacklightCompensation_ON = 1;
	g_onvif_cfg.img_opt.Brightness_min = 0;
	g_onvif_cfg.img_opt.Brightness_max = 100;
	g_onvif_cfg.img_opt.ColorSaturation_min = 0;
	g_onvif_cfg.img_opt.ColorSaturation_max = 100;
	g_onvif_cfg.img_opt.Contrast_min = 0;
	g_onvif_cfg.img_opt.Contrast_max = 100;
	g_onvif_cfg.img_opt.Exposure_AUTO = 1;
	g_onvif_cfg.img_opt.Exposure_MANUAL = 0;
	g_onvif_cfg.img_opt.MinExposureTime_min = 10;
	g_onvif_cfg.img_opt.MinExposureTime_max = 10;
	g_onvif_cfg.img_opt.MaxExposureTime_min = 10;
	g_onvif_cfg.img_opt.MaxExposureTime_max = 320000;
	g_onvif_cfg.img_opt.MinGain_min = 0;
	g_onvif_cfg.img_opt.MinGain_max = 0;
	g_onvif_cfg.img_opt.MaxGain_min = 0;
	g_onvif_cfg.img_opt.MaxGain_max = 100;
	g_onvif_cfg.img_opt.IrCutFilter_ON = 1;
	g_onvif_cfg.img_opt.IrCutFilter_OFF = 1;
	g_onvif_cfg.img_opt.IrCutFilter_AUTO = 1;
	g_onvif_cfg.img_opt.Sharpness_min = 0;
	g_onvif_cfg.img_opt.Sharpness_max = 100;
	g_onvif_cfg.img_opt.WideDynamicRange_OFF = 1;
	g_onvif_cfg.img_opt.WideDynamicRange_ON = 1;
	g_onvif_cfg.img_opt.WideDynamicRange_Level_min = 0;
	g_onvif_cfg.img_opt.WideDynamicRange_Level_max = 100;
	g_onvif_cfg.img_opt.WhiteBalance_AUTO = 1;
	g_onvif_cfg.img_opt.WhiteBalance_MANUAL = 0;

	// read config file
	
	FILE * fp = fopen("config.xml", "r");
	if (NULL == fp)
	{
		return;
	}
	
	fseek(fp, 0, SEEK_END);
	
	int len = ftell(fp);
	if (len <= 0)
	{
		fclose(fp);
		return;
	}
	fseek(fp, 0, SEEK_SET);
	
	char * xml_buff = (char *) malloc(len + 1);	
	if (NULL == xml_buff)
	{
		fclose(fp);
		return;
	}

	int rlen = fread(xml_buff, 1, len, fp);
	
	fclose(fp);

	onvif_parse_cfg(xml_buff, rlen); //分析config xml，设置 g_onvif_cfg 选项

	free(xml_buff);
}

ONVIF_NET_INF * onvif_add_net_interface()
{
	ONVIF_NET_INF * p_net_inf = (ONVIF_NET_INF *) malloc(sizeof(ONVIF_NET_INF));
	if (NULL == p_net_inf)
	{
		return NULL;
	}

	memset(p_net_inf, 0, sizeof(ONVIF_NET_INF));

    snprintf(p_net_inf->token, ONVIF_TOKEN_LEN, "eth%d", g_onvif_cls.netinf_idx);
    snprintf(p_net_inf->name, ONVIF_NAME_LEN, "eth%d", g_onvif_cls.netinf_idx);

    g_onvif_cls.netinf_idx++;

	ONVIF_NET_INF * p_tmp = g_onvif_cfg.network.interfaces;
	if (NULL == p_tmp)
	{
		g_onvif_cfg.network.interfaces = p_net_inf;
	}
	else
	{
		while (p_tmp && p_tmp->next) p_tmp = p_tmp->next;

		p_tmp->next = p_net_inf;
	}

	return p_net_inf;
}

void onvif_init_net_interfaces()
{
#if __WIN32_OS__

	IP_ADAPTER_ADDRESSES addr[16], *paddr;
	DWORD len = sizeof(addr);
	
	if (NO_ERROR == GetAdaptersAddresses(AF_INET, 0, 0, addr, &len) && len >= sizeof(IP_ADAPTER_ADDRESSES))
	{
		paddr = addr;
		while (paddr)
		{
			if (paddr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
			{
				paddr = paddr->Next;
				continue;
			}
			
			ONVIF_NET_INF * p_net_inf = onvif_add_net_interface();
			if (NULL == p_net_inf)
			{
				return;
			}

			sprintf(p_net_inf->hwaddr, "%02X:%02X:%02X:%02X:%02X:%02X", paddr->PhysicalAddress[0], paddr->PhysicalAddress[1],
				paddr->PhysicalAddress[2], paddr->PhysicalAddress[3], paddr->PhysicalAddress[4], paddr->PhysicalAddress[5]);

			p_net_inf->mtu = paddr->Mtu;
			p_net_inf->ipv4_enabled = (paddr->Flags & IP_ADAPTER_IPV4_ENABLED);
			p_net_inf->fromdhcp = (paddr->Flags & IP_ADAPTER_DHCP_ENABLED);

			IP_ADAPTER_UNICAST_ADDRESS * p_ipaddr = paddr->FirstUnicastAddress;
			while (p_ipaddr)
			{
				if (paddr->FirstUnicastAddress->Address.lpSockaddr->sa_family == AF_INET)
				{
					struct sockaddr_in * p_inaddr = (struct sockaddr_in *)paddr->FirstUnicastAddress->Address.lpSockaddr;

					strcpy(p_net_inf->ipv4_addr, inet_ntoa(p_inaddr->sin_addr));
					p_net_inf->prefix_len = 24;
					break;
				}

				p_ipaddr = p_ipaddr->Next;
			}
			
			p_net_inf->enabled = TRUE;
		
			paddr = paddr->Next;
		}
	}

#elif __LINUX_OS__

	int socket_fd;
	struct sockaddr_in *sin;
	struct ifreq *ifr;
	struct ifreq ifreq;
	struct ifconf conf;
	char buff[BUFSIZ];
	int num;
	
	socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
	
	conf.ifc_len = BUFSIZ;
	conf.ifc_buf = buff;
	
	ioctl(socket_fd, SIOCGIFCONF, &conf);
	
	num = conf.ifc_len / sizeof(struct ifreq);
	ifr = conf.ifc_req;
	
	for (int i=0; i<num; i++)
	{		
		struct sockaddr_in *sin = (struct sockaddr_in *)(&ifr->ifr_addr);

		if (ifr->ifr_addr.sa_family != AF_INET)
		{
			ifr++;
			continue;
		}
		
		ioctl(socket_fd, SIOCGIFFLAGS, ifr);
		if ((ifr->ifr_flags & IFF_LOOPBACK) == 0)
		{
			ONVIF_NET_INF * p_net_inf = onvif_add_net_interface();
			if (NULL == p_net_inf)
			{
				break;
			}

			p_net_inf->mtu = ifr->ifr_mtu;
			p_net_inf->ipv4_enabled = 1;
			p_net_inf->fromdhcp = 0;
			p_net_inf->prefix_len = 24;
			p_net_inf->enabled = TRUE;

			strcpy(p_net_inf->ipv4_addr, inet_ntoa(sin->sin_addr));
			strncpy(p_net_inf->name, ifr->ifr_name, sizeof(p_net_inf->name)-1);

			strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
	        if (ioctl(socket_fd, SIOCGIFHWADDR, &ifreq) < 0) 
	        {
	        	ifr++;
	            continue;
	        }

			snprintf(p_net_inf->hwaddr, sizeof(p_net_inf->hwaddr), "%02X:%02X:%02X:%02X:%02X:%02X", 
				(unsigned char)ifreq.ifr_hwaddr.sa_data[0], (unsigned char)ifreq.ifr_hwaddr.sa_data[1], (unsigned char)ifreq.ifr_hwaddr.sa_data[2],
				(unsigned char)ifreq.ifr_hwaddr.sa_data[3], (unsigned char)ifreq.ifr_hwaddr.sa_data[4], (unsigned char)ifreq.ifr_hwaddr.sa_data[5]);				
			
		}
		
		ifr++;
	}

	closesocket(socket_fd);
	
#endif

	
}

void onvif_init_net()
{
	// init host name
    g_onvif_cfg.network.hostname_fromdhcp = 0;
    g_onvif_cfg.network.set_hostname_need_reboot = 1;
    gethostname(g_onvif_cfg.network.hostname, sizeof(g_onvif_cfg.network.hostname));

	// init dns setting
    g_onvif_cfg.network.dns_fromdhcp = 0;
    strcpy(g_onvif_cfg.network.dns_server[0], "192.168.1.1");

    // init ntp settting
    g_onvif_cfg.network.ntp_fromdhcp = 0;
    strcpy(g_onvif_cfg.network.ntp_server[0], "time.windows.com");

    // init network protocol
    g_onvif_cfg.network.http_support = 1;
    g_onvif_cfg.network.https_support = 0;
    g_onvif_cfg.network.rtsp_support = 1;
    g_onvif_cfg.network.http_enable = 1;
    g_onvif_cfg.network.https_enable = 0;
    g_onvif_cfg.network.rtsp_enable = 1;
    g_onvif_cfg.network.http_port[0] = 80;
    g_onvif_cfg.network.https_port[0] = 443;
    g_onvif_cfg.network.rtsp_port[0] = 554;

    // init default gateway
    strcpy(g_onvif_cfg.network.gateway[0], "192.168.1.1");

    // init network interface
    onvif_init_net_interfaces();
}

void onvif_init()
{
	memset(&g_onvif_cfg, 0, sizeof(ONVIF_CFG));
	memset(&g_onvif_cls, 0, sizeof(ONVIF_CLS));
	
	onvif_init_cfg();

    onvif_init_net();    
	
	onvif_eua_init();	

	if (g_onvif_cfg.serv_port > 0 && g_onvif_cfg.serv_port < 65535) 
	{
		g_onvif_cls.local_port = g_onvif_cfg.serv_port;
	}
	else
	{
		g_onvif_cls.local_port = 8000;
	}

	if (strlen(g_onvif_cfg.serv_ip) > 0)
	{
		strcpy(g_onvif_cls.local_ipstr, g_onvif_cfg.serv_ip);
	}
	else 
	{
		const char * ip = onvif_get_local_ip();
		if (ip)
		{
			strcpy(g_onvif_cls.local_ipstr, ip);
		}
	}
}

PTZ_PRESET * onvif_find_preset(const char * profile_token, const char  * preset_token)
{
    ONVIF_PROFILE * p_profile = onvif_find_profile(profile_token);
    if (NULL == p_profile || NULL == p_profile->ptz_node)
    {
        return NULL;
    }

	int i;

    for (i = 0; i < PTZ_MAX_PRESETS; i++)
    {
        if (strcmp(preset_token, p_profile->ptz_node->config.presets[i].token) == 0)
        {
            break;
        }
    }

    if (i == PTZ_MAX_PRESETS)
    {
        return NULL;
    }

    return &p_profile->ptz_node->config.presets[i];
}

PTZ_PRESET * onvif_get_idle_preset(const char * profile_token)
{
    ONVIF_PROFILE * p_profile = onvif_find_profile(profile_token);
    if (NULL == p_profile || NULL == p_profile->ptz_node)
    {
        return NULL;
    }

	int i;

    for (i = 0; i < PTZ_MAX_PRESETS; i++)
    {
        if (p_profile->ptz_node->config.presets[i].used_flag == 0)
        {
            break;
        }
    }

    if (i == PTZ_MAX_PRESETS)
    {
        return NULL;
    }

    return &p_profile->ptz_node->config.presets[i];
}

ONVIF_NET_INF * onvif_find_net_inf(const char * token)
{
    ONVIF_NET_INF * p_net_inf = g_onvif_cfg.network.interfaces;

    while (p_net_inf)
    {
        if (strcmp(p_net_inf->token, token) == 0)
        {
            break;
        }

        p_net_inf = p_net_inf->next;
    }

    return p_net_inf;
}


